package com.xayy.core.antlr4.utils;
import groovy.lang.Binding;
import groovy.lang.GroovyClassLoader;
import groovy.lang.GroovyObject;
import groovy.lang.Script;
import org.codehaus.groovy.control.CompilerConfiguration;
import org.codehaus.groovy.control.customizers.ImportCustomizer;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Groovy 脚本执行工具类
 */
public class GroovyScriptUtils {

    // 缓存已编译的 Groovy 类
    private static final ConcurrentHashMap<String, Class<?>> scriptCache = new ConcurrentHashMap<>();
    // 基本导入配置
    private static final CompilerConfiguration DEFAULT_CONFIG = createDefaultConfiguration();
    // 使用单独的类加载器
    private static final GroovyClassLoader groovyClassLoader = new GroovyClassLoader(GroovyScriptUtils.class.getClassLoader(),DEFAULT_CONFIG);
    /**
     * 创建默认配置
     */
    private static CompilerConfiguration createDefaultConfiguration() {
        CompilerConfiguration config = new CompilerConfiguration();

        // 导入定制器
        ImportCustomizer imports = new ImportCustomizer();
        imports.addStarImports("java.util", "com.alibaba.fastjson");
        imports.addStaticStars("java.lang.Math");

        config.addCompilationCustomizers(imports);
        return config;
    }

    /**
     * 执行 Groovy 脚本中的方法
     */
    public static Object execute(String scriptContent, String functionName, Object... args) {
        return executeInternal(scriptContent, functionName, null, args);
    }

    /**
     * 使用 Binding 执行 Groovy 脚本中的方法
     */
    public static Object executeWithBinding(String scriptContent, String functionName, Map<String, Object> variables) {
        return executeInternal(scriptContent, functionName, variables, null);
    }

    /**
     * 内部执行方法
     */
    private static Object executeInternal(String scriptContent, String functionName,
                                          Map<String, Object> variables, Object... args) {
        try {
            // 获取或编译类
            Class<?> groovyClass = scriptCache.computeIfAbsent(scriptContent, k ->
                    compileClass(scriptContent)
            );

            // 执行脚本
            if (variables != null) {
                return executeWithBinding(groovyClass, functionName, variables);
            } else {
                return executeDirect(groovyClass, functionName, args);
            }
        } catch (Exception e) {
            throw new GroovyExecutionException("执行 Groovy 脚本失败: " + e.getMessage(), e);
        }
    }

    /**
     * 直接参数执行
     */
    private static Object executeDirect(Class<?> groovyClass, String functionName,
                                        Object... args) throws Exception {
        GroovyObject groovyObject = (GroovyObject) groovyClass.getDeclaredConstructor().newInstance();
        return groovyObject.invokeMethod(functionName, args);
    }

    /**
     * Binding 方式执行
     */
    private static Object executeWithBinding(Class<?> groovyClass, String functionName,
                                             Map<String, Object> variables) throws Exception {
        // 创建 Binding 并设置变量
        Binding binding = new Binding();
        variables.forEach(binding::setVariable);

        // 创建脚本实例
        Script script = (Script) groovyClass.getDeclaredConstructor(Binding.class).newInstance(binding);

        // 运行脚本初始化
        script.run();

        // 调用目标方法
        return script.invokeMethod(functionName, null);
    }

    /**
     * 编译 Groovy 类
     */
    private static Class<?> compileClass(String scriptContent) {
        return groovyClassLoader.parseClass(scriptContent);
    }

    /**
     * 自定义异常
     */
    public static class GroovyExecutionException extends RuntimeException {
        public GroovyExecutionException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    /**
     * 清除缓存
     */
    public static void clearCache() {
        scriptCache.clear();
        groovyClassLoader.clearCache();
    }

    /**
     * 测试主方法
     */
    public static void main(String[] args) {
        // 测试场景1：直接执行简单加法函数
        String addScript =
                "def add(a, b) { \n" +
                        "   return a + b \n" +
                        "}";

        Object result = execute(addScript, "add", 3, 5);
        System.out.println("加法结果: " + result);  // 预期输出: 加法结果: 8

        // 测试场景2：使用绑定变量执行
        String greetingScript =
                "def greet() { \n" +
                        "   return \"Hello, \" + name + \"! Your score is \" + score \n" +
                        "}";

        Map<String, Object> variables = new HashMap<>();
        variables.put("name", "Alice");
        variables.put("score", 95);

        Object greeting = executeWithBinding(greetingScript, "greet", variables);
        System.out.println(greeting);  // 预期输出: Hello, Alice! Your score is 95

        // 测试场景3：使用Math函数（验证静态导入）
        String mathScript =
                "def calculate() { \n" +
                        "   return Math.sqrt(Math.pow(3, 2) + Math.pow(4, 2)) \n" +  // 计算勾股定理
                        "}";

        Object mathResult = execute(mathScript, "calculate");
        System.out.println("数学计算结果: " + mathResult);  // 预期输出: 数学计算结果: 5.0

        // 测试场景4：使用集合操作（验证包导入）
        String collectionScript =
                "def processList() { \n" +
                        "   def list = [1, 2, 3, 4, 5] \n" +
                        "   return list.findAll { it > 2 }.sum() \n" +  // 筛选大于2的元素并求和
                        "}";

        Object collectionResult = execute(collectionScript, "processList");
        System.out.println("集合操作结果: " + collectionResult);  // 预期输出: 集合操作结果: 12
    }
}